package org.example.route.service.impl;

import org.example.route.constant.OrderConstant;
import org.example.route.constant.PriceConstant;
import org.example.route.constant.TrainConstant;
import org.example.route.constant.StatisticConstant;
import org.example.route.context.BaseContext;
import org.example.route.event.publisher.OrderPublisher;
import org.example.route.event.source.OrderCancelSource;
import org.example.route.mapper.*;
import org.example.route.model.dto.BaseRequest;
import org.example.route.model.dto.StatisticIncomeDTO;
import org.example.route.model.pojo.Order;
import org.example.route.model.pojo.Price;
import org.example.route.model.vo.OrderShowVO;
import org.example.route.model.vo.OrderStatisticVO;
import org.example.route.service.OrderService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private PriceMapper priceMapper;
    @Autowired
    private StationRouteMapper stationRouteMapper;
    @Autowired
    StationMapper stationMapper;
    @Autowired
    private SeatMapper seatMapper;
    @Autowired
    private CarriageMapper carriageMapper;
    @Autowired
    private TrainMapper trainMapper;
    @Autowired
    private OrderPublisher orderPublisher;

    //订单锁
    private final ConcurrentHashMap<Long, Object> orderLocks = new ConcurrentHashMap<>();

    DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    @Transactional
    public List<OrderShowVO> list() {
        Long id = BaseContext.getCurrentId();
        List<Order> orderList = orderMapper.listByUserId(id);
        List<OrderShowVO> orderShowVOList = new ArrayList<>();
        for (Order order : orderList)
        {
            OrderShowVO orderShowVO = new OrderShowVO();

            BeanUtils.copyProperties(order,orderShowVO);

            orderShowVO.setGoId1(priceMapper.getById(order.getPriceId()).getGoId1());
            orderShowVO.setGoId2(priceMapper.getById(order.getPriceId()).getGoId2());
            orderShowVO.setThePrice(priceMapper.getById(order.getPriceId()).getThePrice());
            Price price = priceMapper.getById(order.getPriceId());
            orderShowVO.setGoName1(stationMapper.getNameById(stationRouteMapper.getStationIdById(price.getGoId1())));
            orderShowVO.setGoName2(stationMapper.getNameById(stationRouteMapper.getStationIdById(price.getGoId2())));
            //判断是什么车子
            Long kind = trainMapper.getKindById(stationRouteMapper.getTrainIdById(price.getGoId1()));
            orderShowVO.setGrade(price.getGrade());
            if(kind.equals(TrainConstant.KIND_ORDINARY)){
                //普通车
                orderShowVO.setGradeName(price.getGrade().equals(PriceConstant.GRADE_HIGH) ? "软卧" : price.getGrade().equals(PriceConstant.GRADE_MIDDLE) ? "硬卧" : "硬座");
            }else
            {
                orderShowVO.setGradeName(price.getGrade().equals(PriceConstant.GRADE_HIGH) ? "商务座" : price.getGrade().equals(PriceConstant.GRADE_MIDDLE) ? "一等座" : " 二等座");
            }
            orderShowVO.setStartTime(sdf.format(stationRouteMapper.getStartTimeById(price.getGoId1())));
            orderShowVO.setEndTime(sdf.format(stationRouteMapper.getEndTimeById(price.getGoId2())));
            //SeatName要包含车号，车厢和车位
            orderShowVO.setSeatName(generateSeatName(order.getSeatId()));

            orderShowVO.setCreateTime(sdf.format(order.getCreateTime()));
            orderShowVOList.add(orderShowVO);



        }

        return orderShowVOList;



    }

    //此方法需要上锁
    //需要上锁
    @Override
    public void cancel(BaseRequest baseRequest) {
        Long id = Long.parseLong(baseRequest.getKey());

        Order order = orderMapper.getById(id);
        Object lock = orderLocks.computeIfAbsent(id, k -> new Object());
        synchronized (lock) {

            if (Objects.isNull(order)) {
                throw new RuntimeException("订单不存在");
            }

            order.setStatus(OrderConstant.CANCEL);

            orderMapper.cancelById(id);

            //通知几个监听器修改数据
            OrderCancelSource orderCancelSource = new OrderCancelSource();
            BeanUtils.copyProperties(order, orderCancelSource);
            orderPublisher.publishCancelEvent(orderCancelSource);

        }





    }

    //生成座位名称的算法
    String generateSeatName(Long seatId)

    {
       String seatName = "";
       Long theRow = seatMapper.getTheRowById(seatId);
       Long seatNumber = seatMapper.getSeatNumberById(seatId);

       Long row = (seatNumber / theRow) + 1;
       Long column = seatNumber % theRow;
       Long carriageNumber = carriageMapper.getCarriageNumberById(seatMapper.getCarriageIdById(seatId));
       String serialNumber = trainMapper.getSerialById(carriageMapper.getTrainIdById(seatMapper.getCarriageIdById(seatId)));

       seatName = serialNumber + "  " + carriageNumber + "车厢" + row + "排" + column + "号";
       return seatName;
    }


    @Override
    public OrderStatisticVO totalIncome(StatisticIncomeDTO statisticIncomeDTO) {
        try {
            LocalDateTime startTime =  LocalDateTime.parse(statisticIncomeDTO.getDate(),sdf);
            LocalDateTime endTime;
            List<Order> orders;
            List<OrderShowVO> orderShowVOList = new ArrayList<>();
            if (statisticIncomeDTO.getDateFlag().equals(StatisticConstant.INCOME_YEAR)) {
                     endTime = startTime.plusYears(1);


            } else if (statisticIncomeDTO.getDateFlag().equals(StatisticConstant.INCOME_QUARTER)) {
                     endTime = startTime.plusMonths(3);

            } else if (statisticIncomeDTO.getDateFlag().equals(StatisticConstant.INCOME_MONTH)) {
                    endTime = startTime.plusMonths(1);

            } else if (statisticIncomeDTO.getDateFlag().equals(StatisticConstant.INCOME_DAY)) {
                endTime = startTime.plusDays(1);
            } else {
                      throw new RuntimeException("时间格式不正确！");
            }


            //获取所有订单
            orders = orderMapper.getByStartAndEndTime(startTime,endTime);
            for (Order order : orders)
            {
                OrderShowVO orderShowVO = new OrderShowVO();
                BeanUtils.copyProperties(order,orderShowVO);
                orderShowVO.setThePrice(priceMapper.getById(order.getPriceId()).getThePrice());
                Price price = priceMapper.getById(order.getPriceId());
                orderShowVO.setGoName1(stationMapper.getNameById(stationRouteMapper.getStationIdById(price.getGoId1())));
                orderShowVO.setGoName2(stationMapper.getNameById(stationRouteMapper.getStationIdById(price.getGoId2())));
                //判断是什么车子
                Long kind = trainMapper.getKindById(stationRouteMapper.getTrainIdById(price.getGoId1()));
                if(kind.equals(TrainConstant.KIND_ORDINARY)){
                    //普通车
                    orderShowVO.setGradeName(price.getGrade().equals(PriceConstant.GRADE_HIGH) ? "软卧" : price.getGrade().equals(PriceConstant.GRADE_MIDDLE) ? "硬卧" : "硬座");
                }else
                {
                    orderShowVO.setGradeName(price.getGrade().equals(PriceConstant.GRADE_HIGH) ? "商务座" : price.getGrade().equals(PriceConstant.GRADE_MIDDLE) ? "一等座" : " 二等座");
                }
                orderShowVO.setStartTime(sdf.format(stationRouteMapper.getStartTimeById(price.getGoId1())));
                orderShowVO.setEndTime(sdf.format(stationRouteMapper.getEndTimeById(price.getGoId2())));
                //SeatName要包含车号，车厢和车位
                orderShowVO.setSeatName(generateSeatName(order.getSeatId()));

                orderShowVO.setCreateTime(sdf.format(order.getCreateTime()));
                orderShowVOList.add(orderShowVO);

            }

            Double totalIncome = orderShowVOList.stream().mapToDouble(OrderShowVO::getThePrice).sum();
            return new OrderStatisticVO(totalIncome,orderShowVOList);

        } catch (Exception e) {
            e.printStackTrace();
        }
      return null;
    }
}
